#include <keyMap.h>
#include <type.h>
#include <log.h>
#include <utils.h>
#include <algorithm> 
#include <UserInfo.h>

EXTERN_C_BEGIN
    struct keyMapEntry
    {
        int    level;
        const  char* str;
        size_t str_len;
    };

#define KEY_DESC(v, str) {v, #str, sizeof(#str) - 1}
#define KEY_DESC_END {0, nullptr, 0}
    LOCAL constexpr keyMapEntry log_map[] =
    {
        KEY_DESC(LOG_LVL_FATAL, FATAL),
        KEY_DESC(LOG_LVL_ERROR, ERROR),
        KEY_DESC(LOG_LVL_WARN,  WARN),
        KEY_DESC(LOG_LVL_INFO,  INFO),
        KEY_DESC(LOG_LVL_DEBUG, DEBUG),
        KEY_DESC(LOG_LVL_TRACE, TRACE),
        KEY_DESC_END
    };

    LOCAL constexpr keyMapEntry switch_map[] =
    {
        KEY_DESC(TRUE,  ON),
        KEY_DESC(FALSE, OFF),
        KEY_DESC_END
    };

    LOCAL constexpr keyMapEntry bool_map[] =
    {
        KEY_DESC(TRUE,  TRUE),
        KEY_DESC(FALSE, FALSE),
        KEY_DESC_END
    };
    
    LOCAL constexpr keyMapEntry status_map[] =
    {
        KEY_DESC(FALSE,  Stoped),
        KEY_DESC(TRUE,   Running),
        KEY_DESC_END
    };

    LOCAL constexpr keyMapEntry userPermission_map[] =
    {
        KEY_DESC(BANNED,  BANNED),
        KEY_DESC(GUEST,   GUEST),
        KEY_DESC(ADMIN,   ADMIN),
        KEY_DESC(OPERATOR,    OPERATOR),
        KEY_DESC(SUPER_ADMIN, SUPER_ADMIN),
        KEY_DESC_END
    };

    LOCAL constexpr const keyMapEntry* all_maps[] =
    {
        log_map,
        switch_map,
        bool_map,
        status_map,
        userPermission_map
    };

    bool string_to_value(MapType map_index, const std::string& str, int& out)
    {
        if (map_index < MAP_BEGIN || map_index >= NELEMENTS(all_maps))
        {
            return false;
        }

        std::string upper_str = str;
        std::transform(upper_str.begin(), upper_str.end(), upper_str.begin(), ::toupper);

        const keyMapEntry* map = all_maps[map_index];
        for (int idx = 0; map[idx].str != nullptr; ++idx)
        {
            if ((upper_str.length() == map[idx].str_len) && utils::stricmp(upper_str, map[idx].str))
            {
                out = map[idx].level;
                return true;
            }
        }
        return false;
    }

    const char* value_to_string(MapType map_index, int value)
    {
        if (map_index < MAP_BEGIN || map_index >= NELEMENTS(all_maps))
        {
            return "UNKNOWN";
        }
        const keyMapEntry* map = all_maps[map_index];
        for (int idx = 0; map[idx].str != nullptr; ++idx)
        {
            if (map[idx].level == value)
            {
                return map[idx].str;
            }
        }
        return "UNKNOWN";
    }

EXTERN_C_END